<?php


namespace app\services\utils;




class SnowflakeService
{
    private $timestampBits = 41; // 时间戳占用位数
    private $datacenterIdBits = 5; // 数据中心 ID 占用位数
    private $workerIdBits = 5; // 工作节点 ID 占用位数
    private $sequenceBits = 12; // 序列号占用位数

    private $datacenterId;
    private $workerId;
    private $epoch = 1609459200000; // 自定义起始时间戳（毫秒级），此处为2021-01-01 00:00:00

    private $lastTimestamp = -1;
    private $sequence = 0;

    public function __construct($datacenterId, $workerId)
    {
        // 设置数据中心 ID 和工作节点 ID
        $this->datacenterId = $datacenterId;
        $this->workerId = $workerId;
    }

    public function generateOrderNumber()
    {
        $timestamp = $this->getTimestamp();

        // 处理时钟回拨问题
        if ($timestamp < $this->lastTimestamp) {
            throw new \Exception("Clock moved backwards");
        }

        // 如果是同一毫秒内生成的，则递增序列号
        if ($timestamp == $this->lastTimestamp) {
            $this->sequence = ($this->sequence + 1) & ((1 << $this->sequenceBits) - 1); // 取低 $sequenceBits 位
            if ($this->sequence == 0) {
                // 序列号溢出，等待下一毫秒
                $timestamp = $this->waitForNextMillis($this->lastTimestamp);
            }
        } else {
            $this->sequence = 0; // 不同毫秒内，序列号重置为0
        }

        $this->lastTimestamp = $timestamp;

        // 生成订单号
        $orderNumber = (($timestamp - $this->epoch) << ($this->datacenterIdBits + $this->workerIdBits + $this->sequenceBits))
            | ($this->datacenterId << ($this->workerIdBits + $this->sequenceBits))
            | ($this->workerId << $this->sequenceBits)
            | $this->sequence;

        return $orderNumber;
    }

    private function getTimestamp()
    {
        return floor(microtime(true) * 1000);
    }

    private function waitForNextMillis($lastTimestamp)
    {
        $timestamp = $this->getTimestamp();
        while ($timestamp <= $lastTimestamp) {
            $timestamp = $this->getTimestamp();
        }
        return $timestamp;
    }
}
